#include "crossbit/ExecutionEngine.h"
#include "arch/ia32/IA32Interpreter.h"
#include "crossbit/Exit.h"
#include "crossbit/Profiler.h"
#include "vector"
using namespace crossbit;

// #define DEBUG
//#define LINK

void ExecutionEngine::run()
{
	ee_memory_image->load();
	ee_interpreter->initStack( ee_memory_image->stack() );

	XTMemAddr entry = ee_memory_image->entry();
       

	int flag = 0;
	TBlock* pre_tblock = NULL;
	VBlock* pre_vblock = NULL;
	GLOBAL::BUILD_SUPER_BLOCK = 0;

	while (1) {

#ifdef DEBUG

#endif


		TBlock *tblock = ee_tcache -> lookupTBlock(entry);
		VBlock *vblock;
		if (tblock == NULL) {
			ee_builder->getReady(entry);
			XTMemAddr next = entry;

			while( !ee_builder->isEnd() ){
				  next = ee_interpreter -> decode(next, ee_builder);
			}

			vblock = ee_builder -> wrapUp(next);
			tblock = ee_tcache -> requestTBlock();

			

   tblock -> setSPC( entry );
			ee_translator -> encode(vblock, tblock);    
			ee_tcache -> submitTBlock(entry,tblock,vblock);

	if ( 0 &&  entry == 0x804cc0e)
		{
		    vblock-> print(std::cout);
			ee_interpreter->get_state()->dump();
			flag = 1;
			char ppp[100];
			scanf("%s", ppp);
        }


		}

		XTMemAddr enter = tblock->enterAddr();

#ifdef DEBUG

#endif


#ifdef LINK

		if( pre_tblock != NULL )
		{
		    VInst *inst = *pre_vblock->rbegin();
		    if( inst->getOpcode() == OP_BRANCH && inst->getOperand(4).reg == 0)
		    {
		        ee_trace_manager -> directLinkTo( pre_tblock , GLOBAL::last_exit , tblock );
		    }
		    else if(inst->getOpcode() == OP_JMP && inst->getOperand(1).reg != 0)
		    {
		        ee_trace_manager -> indirectLinkTo( pre_tblock , GLOBAL::last_exit , tblock );
		    }
  }
#endif
        

    CONTEXT_SAVE;

	 		((void (*)()) enter) ();

    CONTEXT_RESTORE;


	    if (flag)
		{
		    printf("***********************\n");
			ee_interpreter->get_state()->dump();
            char p[100];
			scanf("%s", p);
		}

      
		Exit exit = GLOBAL::tblock_stub->getExit(GLOBAL::last_exit);
		if (exit.why == ExitReason::SYSCALLEXIT) {
			(*ee_syscall_handler)();
		}

		entry = exit.next;

		pre_tblock = GLOBAL::tblock_stub;
		pre_vblock = GLOBAL::vblock_stub;
	}

}

